﻿using SimpleCrawler.DAL;
using SimpleCrawler.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using System.Net;
using System.IO.Compression;
using System.IO;
using System.Text;
using System.Collections;
using System.Threading;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium;
using System.Reflection;
using System.Drawing;
using System.Collections.ObjectModel;
using Baidu.Aip.Ocr;
using SimpleCrawler.Entity;

namespace SimpleCrawler.Crawler.WebCrawler
{
    public class ZhiHuCrawler : CrawlerBase
    {
        CrawlerDAL dal;
        public ZhiHuCrawler() : base(1009, "知乎")
        {
            dal = AppServiceProvider.ServiceProvider.GetService<CrawlerDAL>();
        }

        public override void GetStartedPageUrl()
        {
            RequestUrl = $"https://www.zhihu.com/search?q={System.Web.HttpUtility.UrlEncode(CrawlerTask.KeyWord)}&range=3m&type=content";
        }

        private int count=0;
        public override async Task<string> GetTargetHtmlString()
        {
            List<WD_Question> questions = new List<WD_Question>();
            string rootpath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            using (ChromeDriver driver = new ChromeDriver(rootpath))
            {
                driver.Manage().Window.Maximize();
                driver.Navigate().GoToUrl(RequestUrl);
                if (string.IsNullOrEmpty(driver.Title))
                {
                    return null;
                }
                ((IJavaScriptExecutor)driver).ExecuteScript("var dom=document.getElementsByClassName('SearchTab-bottomShadow')[0];dom.remove(true);dom=document.getElementsByClassName('AppHeader')[0];dom.remove(true);");

                var count = 1;
                IWebElement dom;
                Point position;
                Regex Answer = new Regex(@"Post-RichText"">([\s\S]*?)</div>[\s\S]*?(\d{4}-\d{1,2}-\d{1,2})[\s\S]*?VoteButton--up[\s\S]*?赞同([\s\S]*?)</button>");

                Regex otherAnswers = new Regex(@"<div class=""List"">[\s\S]*?class=""Card""");
                Regex otherAnswer = new Regex(@"<span class=""RichText[\s\S]*?>([\s\S]*?)</span></div>[\s\S]*?ContentItem-time[\s\S]*?(\d{4}-\d{1,2}-\d{1,2})[\s\S]*?VoteButton--up[\s\S]*?赞同[\s\S]*?</button>");

                try
                {
                    beginning:
                    driver.SwitchTo().Window(driver.WindowHandles[0]);
                    dom = driver.FindElement(By.XPath($"//div[@class=\"List-item\"][{count}]//a"));
                    position = dom.Location;
                    ((IJavaScriptExecutor)driver).ExecuteScript($"window.scrollTo(0,{position.Y});");
                    dom.Click();
                    //action
                    WD_Question question = new WD_Question();
                    question.Answers = new List<WD_Answer>();
                    driver.SwitchTo().Window(driver.WindowHandles[1]);
                    Thread.Sleep(10 * 1000);
                    //url过滤
                    if (Filter != null && Filter.Contains(driver.Url))
                    {
                        Logger.Error($"已过滤的问答,link=>{driver.Url}");
                        goto ending;
                    }
                    Filter.Add(driver.Url);
                    //
                    question.SourceSite = this.CrawlerID;
                    question.KeyWord = this.CrawlerTask.KeyWord;
                    question.SourceUrl = driver.Url;
                    if (driver.Url.IndexOf("/question/") > 0)
                    {
                        try
                        {
                            dom = driver.FindElement(By.XPath($"//h1[@class=\"QuestionHeader-title\"]"));
                            question.Question = dom.GetAttribute("innerHTML");
                            try
                            {
                                dom = driver.FindElement(By.XPath($"//a[@class=\"QuestionMainAction\"]"));
                                dom.Click();
                                Thread.Sleep(3 * 1000);
                            }
                            catch { }
                            MatchCollection MotherAnswers = otherAnswer.Matches(otherAnswers.Match(driver.PageSource).ToString());
                            foreach (Match item in MotherAnswers)
                            {
                                WD_Answer answer = new WD_Answer();
                                try
                                {
                                    answer.Answer = item.Groups[1].ToString();
                                    answer.AnswerLen = answer.Answer.Length;
                                    answer.CreateDate = DateTime.Parse(item.Groups[2].ToString());
                                    if (!string.IsNullOrWhiteSpace(item.Groups[3].ToString()))
                                        answer.ZanCount = int.Parse(item.Groups[3].ToString().Replace("<!-- -->", "").Trim());
                                }
                                catch (Exception ex)
                                {
                                    Logger.Error($"答案匹配出错,link=>{driver.Url}");
                                    goto ending;
                                }
                                if (!string.IsNullOrEmpty(answer.Answer))
                                {
                                    question.Answers.Add(answer);
                                }
                            }
                        }
                        catch
                        {
                            goto ending;
                        }

                    }
                    else
                    {
                        try
                        {
                            dom = driver.FindElement(By.XPath($"//h1[@class=\"Post-Title\"]"));
                            question.Question = dom.Text;
                            WD_Answer answer = new WD_Answer();
                            Match Amatch = Answer.Match(driver.PageSource);
                            if (Amatch.Success)
                            {
                                answer.Answer = Amatch.Groups[1].ToString();
                                answer.AnswerLen = answer.Answer.Length;
                                answer.CreateDate = DateTime.Parse(Amatch.Groups[2].ToString());
                                if (!string.IsNullOrWhiteSpace(Amatch.Groups[3].ToString()))
                                    answer.ZanCount = int.Parse(Amatch.Groups[3].ToString().Replace("<!-- -->","").Trim());
                            }
                            else
                            {
                                Logger.Error($"答案匹配出错,link=>{driver.Url}");
                            }
                            if (!string.IsNullOrEmpty(answer.Answer))
                            {
                                question.Answers.Add(answer);
                            }
                        }
                        catch
                        {
                            Logger.Error($"答案匹配出错,link=>{driver.Url}");
                            goto ending;
                        }
                    }
                    if (string.IsNullOrEmpty(question.Question))
                    {
                        Logger.Error($"问题匹配出错,link=>{driver.Url}");
                        goto ending;
                    }
                    questions.Add(question);
                    if(question.Answers.Count==0)
                        Logger.Error($"未匹配到答案,link=>{driver.Url}");
                    ending:
                    //driver.Close();
                    ((IJavaScriptExecutor)driver).ExecuteScript("window.close()");
                    count++;
                    if (count <= CrawlerTask.Total)
                        goto beginning;
                }
                catch (Exception ex)
                {
                    driver.Quit();
                }
                driver.Quit();
            }
            if (questions.Count > 0)
            {
                var result = await SaveToDB(questions);
                if (!string.IsNullOrEmpty(result.Content))
                {
                    Logger.Error(result.Content);
                }
                count = result.Count;
            }
            return count.ToString();
        }

        public override async Task<int> GetResultContent(string html)
        {
            return count;
        }
        protected async Task<(int Count, string Content)> SaveToDB(List<WD_Question> list)
        {
            return await dal.AddQuestions(list).ConfigureAwait(continueOnCapturedContext: false);
        }
    }
}
